﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace CIS.Web
{
	public class DomainRoute : Route
	{
		private Regex domainRegex;
		private Regex pathRegex;

		public string Domain { get; set; }

		public DomainRoute(string domain, string url, RouteValueDictionary defaults) : base(url, defaults, new MvcRouteHandler())
		{
			Domain = domain;
		}

		public DomainRoute(string domain, string url, RouteValueDictionary defaults, IRouteHandler routeHandler) : base(url, defaults, routeHandler)

		{
			Domain = domain;
		}

		public DomainRoute(string domain, string url, object defaults) : base(url, new RouteValueDictionary(defaults), new MvcRouteHandler())
		{
			Domain = domain;
		}

		public DomainRoute(string domain, string url, object defaults, IRouteHandler routeHandler) : base(url, new RouteValueDictionary(defaults), routeHandler)
		{
			Domain = domain;
		}

		public override RouteData GetRouteData(HttpContextBase httpContext)
		{
			// 构造 regex
			domainRegex = CreateRegex(Domain);
			pathRegex = CreateRegex(Url);
			// 请求信息
			string requestDomain = httpContext.Request.Headers["host"];
			if (!string.IsNullOrEmpty(requestDomain))
			{
				if (requestDomain.IndexOf(":") > 0)
				{
					requestDomain = requestDomain.Substring(0, requestDomain.IndexOf(":"));
				}
			}
			else
			{
				requestDomain = httpContext.Request.Url.Host;
			}
			string requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;

			// 匹配域名和路由
			Match domainMatch = domainRegex.Match(requestDomain);
			Match pathMatch = pathRegex.Match(requestPath);

			// 路由数据
			RouteData data = null;
			if (domainMatch.Success && pathMatch.Success)
			{
				data = new RouteData(this, RouteHandler);
				// 添加默认选项
				if (Defaults != null)
				{
					foreach (KeyValuePair<string, object> item in Defaults)
					{
						data.Values[item.Key] = item.Value;
					}
				}

				// 匹配域名路由
				for (int i = 1; i < domainMatch.Groups.Count; i++)
				{
					Group group = domainMatch.Groups[i];
					if (group.Success)
					{
						string key = domainRegex.GroupNameFromNumber(i);
						if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0))
						{
							if (!string.IsNullOrEmpty(group.Value))
							{
								data.Values[key] = group.Value;
							}
						}
					}
				}

				// 匹配域名路径
				for (int i = 1; i < pathMatch.Groups.Count; i++)
				{
					Group group = pathMatch.Groups[i];
					if (group.Success)
					{
						string key = pathRegex.GroupNameFromNumber(i);

						if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0))
						{
							if (!string.IsNullOrEmpty(group.Value))
							{
								data.Values[key] = group.Value;
							}
						}
					}
				}
			}

			return data;
		}

		public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
		{
			return base.GetVirtualPath(requestContext, RemoveDomainTokens(values));
		}

		public DomainData GetDomainData(RequestContext requestContext, RouteValueDictionary values)
		{
			// 获得主机名
			string hostname = Domain;
			foreach (KeyValuePair<string, object> pair in values)
			{
				hostname = hostname.Replace("{" + pair.Key + "}", pair.Value.ToString());
			}

			// Return 域名数据
			return new DomainData
			{
				Protocol = "http",
				HostName = hostname,
				Fragment = ""
			};
		}

		private Regex CreateRegex(string source)
		{
			// 替换
			source = source.Replace("/", @"\/?");
			source = source.Replace(".", @"\.?");
			source = source.Replace("-", @"\-?");
			source = source.Replace("{", @"(?<");
			source = source.Replace("}", @">([a-zA-Z0-9_]*))");

			return new Regex("^" + source + "$", RegexOptions.IgnoreCase);
		}

		private RouteValueDictionary RemoveDomainTokens(RouteValueDictionary values)
		{
			Regex tokenRegex = new Regex(@"({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?");
			Match tokenMatch = tokenRegex.Match(Domain);
			for (int i = 0; i < tokenMatch.Groups.Count; i++)
			{
				Group group = tokenMatch.Groups[i];
				if (group.Success)
				{
					string key = group.Value.Replace("{", "").Replace("}", "");
					if (values.ContainsKey(key))
						values.Remove(key);
				}
			}

			return values;
		}
	}
	public class DomainData
	{
		public string Protocol { get; set; }
		public string HostName { get; set; }
		public string Fragment { get; set; }
	}

	//public class deal : IHttpHandler
	//{
	//	bool IHttpHandler.IsReusable
	//	{
	//		get
	//		{
	//			return true;
	//		}
	//	}

	//	bool IsReusable { get; }

	//	public void ProcessRequest(HttpContext context)
	//	{
	//		throw new NotImplementedException();
	//	}

	//	void IHttpHandler.ProcessRequest(HttpContext context)
	//	{
	//		//获取当前访问的重写过的虚假URL，path值例：/websitetest/user/abc
	//		string path = context.Request.Path.ToLower();        //分析出参数,path值例：abc
	//		path = path.Substring(path.LastIndexOf("/") + 1);        //Default.aspx?name=abc
	//		context.Server.Execute("~/Default.aspx?name=" + path);
	//	}

	//	//3、最后要在Web.Config文件里面定义这个由ASP.NET处理的虚拟路径，以下代码加在<system.web>节点里面
	//	//<httpHandlers>
	//	//<!-- verb动词，请求类型get or post or * -->
	//	//<!-- path被请求文件的位置和文件名 -->
	//	//<!-- type处理类 -->
	//	//<add verb="*" path="user/*" type="deal" />
	//	//</httpHandlers>
	//	//注意：我说明一下，我当初犯的一个错误，很郁闷。path不能直接写成path="*"，一定要虚拟的加一层user/或者其他名字，因为处理参数的Default.aspx不能和要虚拟的路径在同一层目录下，否则会循环调用。		
	//}
}